package com.econ.powercloud.ems.service.biz;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.econ.powercloud.clickhouse.entity.EmsStatisticalDay;
import com.econ.powercloud.common.base.facade.pojo.PageResult;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.DeviceType;
import com.econ.powercloud.ems.common.enums.ReportIdType;
import com.econ.powercloud.ems.common.util.DateTimeUtil;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.EmsColumnConfig;
import com.econ.powercloud.ems.dal.entity.EmsDevice;
import com.econ.powercloud.ems.pojo.ApiDataVO;
import com.econ.powercloud.ems.pojo.ReportVO;
import com.econ.powercloud.ems.pojo.RedisHourDataVO;
import com.econ.powercloud.ems.pojo.requestVO.BatchReportRequestVO;
import com.econ.powercloud.ems.pojo.requestVO.ReportRequestVO;
import com.econ.powercloud.ems.service.dao.EmsColumnConfigDAO;
import com.econ.powercloud.ems.service.dao.EmsDeviceDAO;
import com.econ.powercloud.ems.service.dao.clickhouse.EmsStatisticalDayDAO;
import com.econ.powercloud.ems.util.RedisCacheUtil;
import com.econ.powercloud.ems.util.TimeUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description :报表 service
 * @Date : 2021/9/24 10:44
 * @Modified by : zjf
 */
@Service
public class ElectricBmuReportService {

    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private EmsColumnConfigDAO emsColumnConfigDAO;
    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Autowired
    private ClickHouseBizService clickHouseBizService;
    @Autowired
    private EmsStatisticalDayDAO emsStatisticalDayDAO;


    /**
     * 通过储能站id,储能装置id获取BMU
     * 目前包含: 多功能电表,计量电表
     * @param stationId: 储能站id
     * @param equipmentId: 储能装置id
     */
    public PageResult<List<ApiDataVO>> getBMUList(String stationId, String equipmentId, Integer pageNo, Integer pageSize){
        Page<EmsDevice> page = emsDeviceDAO.getPageByStationIdAndEquipmentIdAndDeviceTypes(stationId,equipmentId,
                Lists.newArrayList(DeviceType.CLUSTER.getCode()),pageNo,pageSize);
        List<ApiDataVO> apiDataVOS = Lists.newArrayList();
        for (EmsDevice emsDevice : page.getRecords()) {
            apiDataVOS.add(ApiDataVO.builder().code(emsDevice.getDeviceCode()).name(emsDevice.getDeviceName()).build());
        }
        return PageResult.<List<ApiDataVO>>builder().data(apiDataVOS)
                .pageNo((int)page.getCurrent()).totalCount((int)page.getTotal()).build();
    }

    /**
     * 获取电表数据的 表头信息
     * @return
     */
    public List<ApiDataVO> getReportHeader(ReportRequestVO requestVO){
        if(requestVO.getReportId() == null){
            requestVO.setReportId(ReportIdType.BMU.getCode());
        }
        List<ApiDataVO> reportHeader = Lists.newLinkedList();
        //获取设备信息
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        if(emsDevice == null){
            return reportHeader;
        }
        //获取该储能站,储能装置下的电表类型的设备有哪些列
        List<EmsColumnConfig> columnList = emsColumnConfigDAO.getListByCondition(requestVO.getStationId(),requestVO.getEquipmentId(),
                emsDevice.getDeviceType(),requestVO.getReportId());
        if(CollectionUtils.isEmpty(columnList)){
            return reportHeader;
        }
        List<EmsColumnConfig> sortList = columnList.stream().sorted(Comparator.comparing(EmsColumnConfig::getSorting)).collect(Collectors.toList());
        sortList.stream().forEach(d->{
            reportHeader.add(ApiDataVO.builder().code(d.getColumnId()).name(d.getColumnName()).build());
        });
        //报表头部需要添加的日期这一列放在第一行
        reportHeader.add(0, ApiDataVO.builder().code(SysConstant.DATE).name(SysConstant.DATE_REMARK).build());
        return reportHeader;
    }

    /**
     * 获取Bmu日报表
     */
    public ReportVO getBmuDataByDay(ReportRequestVO requestVO){
        requestVO.setEndTime(DateTimeUtil.getEndOfDay(new Date(requestVO.getStartTime())));
        Long startOfDay = TimeUtil.getStartOfDay(new Date());
        Date nowDate = new Date();
        String stationId = requestVO.getStationId();
        String equipmentId = requestVO.getEquipmentId();
        String BmuDeviceCode = requestVO.getDeviceCode();
        ReportVO reportVO = ReportVO.builder().build();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getReportHeader(requestVO);
        if(CollectionUtils.isEmpty(reportHeader)){
            return reportVO;
        }
        reportVO.setReportHeader(reportHeader);
        //获取该时间段内报表数据(区分一下报表的类型)
        List<Map<String,String>> bodyList = Lists.newArrayList();
//        List<EmsStatisticalDay> statisticalDayList = emsStatisticalDayDAO.getListByCondition(requestVO.getStationId(),requestVO.getEquipmentId(),
//                requestVO.getDeviceCode(),requestVO.getReportId(),requestVO.getStartTime(),requestVO.getEndTime());
        List<EmsStatisticalDay> statisticalDayList = clickHouseBizService.getBmuDayDataByCondition(requestVO);
        if(CollectionUtils.isEmpty(statisticalDayList) && startOfDay > requestVO.getStartTime()){
            return reportVO;
        }
        //判断起始时间是否为今天
        if(startOfDay <= requestVO.getStartTime()){
            Integer dateToHour = TimeUtil.getDateToHour(new Date());
            List<RedisHourDataVO> RedisHourDataVOList = redisCacheUtil.getBMURedisHistoryDataByHashKey(dateToHour);
            if(CollectionUtils.isEmpty(RedisHourDataVOList)){
                return reportVO;
            }
            for (RedisHourDataVO redisHourDataVO : RedisHourDataVOList) {
                String columnId = redisHourDataVO.getColumnId();
                Long time = redisHourDataVO.getTime();
                Long gmtCreate = redisHourDataVO.getGmtCreate();
                String val = redisHourDataVO.getVal();
                String deviceCode = redisHourDataVO.getDeviceCode();
                if(BmuDeviceCode.equals(deviceCode)){
                    EmsStatisticalDay emsStatisticalDay = EmsStatisticalDay.builder().energyStationId(stationId).energyStationId(equipmentId)
                            .deviceCode(deviceCode).columnId(columnId).val(val).time(time).gmtCreate(nowDate).build();
                    statisticalDayList.add(emsStatisticalDay);
                }
            }
        }
        //按行id排序
        List<EmsStatisticalDay> emsStatisticalDayListSort = Lists.newLinkedList();
        Map<String, List<EmsStatisticalDay>> emsStatisticalDayForColumnId = statisticalDayList.stream().collect(Collectors.groupingBy(d -> d.getColumnId()));
        for (ApiDataVO apiDataVO : reportHeader) {
            List<EmsStatisticalDay> emsStatisticalDayList = emsStatisticalDayForColumnId.get(apiDataVO.getCode());
            if(null != emsStatisticalDayList){
                emsStatisticalDayListSort.addAll(emsStatisticalDayList);
            }
        }
        //报表数据按照时间进行分组
        Map<Long,List<EmsStatisticalDay>> statisticalDayMap = emsStatisticalDayListSort.stream().collect(Collectors.groupingBy(d->d.getTime(),LinkedHashMap::new,Collectors.toList()));
        statisticalDayMap = statisticalDayMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                (oleValue, newValue) -> oleValue, LinkedHashMap::new));
        statisticalDayMap.forEach((k,v)->{
            Map<String,String> map = Maps.newLinkedHashMap();
            //把日期那一列的数据放入
            map.put(SysConstant.DATE, DateTimeUtil.formatDate(new Date(k), DateTimeUtil.HOUR_PATTERN));
            v.stream().forEach(d->{
                map.put(d.getColumnId(),d.getVal());
            });
            bodyList.add(map);
        });
        reportVO.setBodyList(bodyList);
        return reportVO;
    }

    public ReportVO exportData(BatchReportRequestVO batchReportRequestVO, List<String> deviceCodes) {
        ReportVO reportVO = ReportVO.builder().build();
        if (deviceCodes.isEmpty()){
            return reportVO;
        }
        //用于后续排序
        List<Map<String,String>> resBodyList = new ArrayList<>();
        Map<String,Integer> sortMap = new HashMap<>();
        Map<Integer,List<Map<String,String>>> bodyListSortedMap = new HashMap<>();
        for (int i = 0; i < deviceCodes.size(); i++) {
            sortMap.put(deviceCodes.get(i),i);
        }
        ReportRequestVO reportRequestVO = new ReportRequestVO();
        BeanUtils.copyProperties(batchReportRequestVO, reportRequestVO);
        reportRequestVO.setDeviceCode(deviceCodes.get(0));
        Map<String,String> deviceNameMap = new HashMap<>();
        emsDeviceDAO.selectByDeviceCodes(deviceCodes).forEach(d->{
            deviceNameMap.put(d.getDeviceCode(),d.getDeviceName());
        });
        reportRequestVO.setEndTime(DateTimeUtil.getEndOfDay(new Date(reportRequestVO.getStartTime())));
        Long startOfDay = TimeUtil.getStartOfDay(new Date());
        Date nowDate = new Date();
        String stationId = reportRequestVO.getStationId();
        String equipmentId = reportRequestVO.getEquipmentId();
        //获取报表头部信息
        List<ApiDataVO> reportHeader = this.getReportHeader(reportRequestVO);
        if(CollectionUtils.isEmpty(reportHeader)){
            return reportVO;
        }
        reportHeader.add(1,ApiDataVO.builder().code(SysConstant.DEVICE_NAME).name(SysConstant.DEVICE_NAME_REMARK).build());
        reportVO.setReportHeader(reportHeader);
        //获取该时间段内报表数据(区分一下报表的类型)
        List<EmsStatisticalDay> emsStatisticalDays = emsStatisticalDayDAO.selectListByCondition(reportRequestVO, deviceCodes);
        Map<String,List<EmsStatisticalDay>> reportDataMap = emsStatisticalDays.stream().collect(Collectors.groupingBy(EmsStatisticalDay::getDeviceCode));
        if(CollectionUtils.isEmpty(emsStatisticalDays) && startOfDay > reportRequestVO.getStartTime()){
            return reportVO;
        }
        Integer dateToHour = TimeUtil.getDateToHour(new Date());
        List<RedisHourDataVO> RedisHourDataVOList = redisCacheUtil.getBMURedisHistoryDataByHashKey(dateToHour);
        //判断起始时间是否为今天
        for (String key:reportDataMap.keySet()) {
            List<Map<String,String>> bodyList = Lists.newArrayList();
            List<EmsStatisticalDay> bmsData = reportDataMap.get(key);
            if(startOfDay <= reportRequestVO.getStartTime()){
                if(CollectionUtils.isEmpty(RedisHourDataVOList)){
                    return reportVO;
                }
                for (RedisHourDataVO redisHourDataVO : RedisHourDataVOList) {
                    String columnId = redisHourDataVO.getColumnId();
                    Long time = redisHourDataVO.getTime();
                    Long gmtCreate = redisHourDataVO.getGmtCreate();
                    String val = redisHourDataVO.getVal();
                    String deviceCode = redisHourDataVO.getDeviceCode();
                    if(key.equals(deviceCode)){
                        EmsStatisticalDay emsStatisticalDay = EmsStatisticalDay.builder().energyStationId(stationId).energyStationId(equipmentId)
                                .deviceCode(deviceCode).columnId(columnId).val(val).time(time).gmtCreate(nowDate).build();
                        bmsData.add(emsStatisticalDay);
                    }
                }
            }
            //按行id排序
            List<EmsStatisticalDay> emsStatisticalDayListSort = Lists.newLinkedList();
            Map<String, List<EmsStatisticalDay>> emsStatisticalDayForColumnId = bmsData.stream().collect(Collectors.groupingBy(d -> d.getColumnId()));
            for (ApiDataVO apiDataVO : reportHeader) {
                List<EmsStatisticalDay> emsStatisticalDayList = emsStatisticalDayForColumnId.get(apiDataVO.getCode());
                if(null != emsStatisticalDayList){
                    emsStatisticalDayListSort.addAll(emsStatisticalDayList);
                }
            }
            //报表数据按照时间进行分组
            Map<Long,List<EmsStatisticalDay>> statisticalDayMap = emsStatisticalDayListSort.stream().collect(Collectors.groupingBy(d->d.getTime(),LinkedHashMap::new,Collectors.toList()));
            statisticalDayMap = statisticalDayMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                    (oleValue, newValue) -> oleValue, LinkedHashMap::new));
            statisticalDayMap.forEach((k,v)->{
                Map<String,String> map = Maps.newLinkedHashMap();
                //把日期那一列的数据放入
                map.put(SysConstant.DATE, DateTimeUtil.formatDate(new Date(k), DateTimeUtil.HOUR_PATTERN));
                String deviceName = deviceNameMap.get(key);
                map.put(SysConstant.DEVICE_NAME,deviceName);
                v.stream().forEach(d->{
                    map.put(d.getColumnId(),d.getVal());
                });
                bodyList.add(map);
                Integer sortedNum = sortMap.get(key);
                bodyListSortedMap.put(sortedNum,bodyList);
            });
        };
        for (int i = 0;i<bodyListSortedMap.size();i++) {
            List<Map<String,String>> resList = bodyListSortedMap.get(i);
            resBodyList.addAll(resList);
        };
        reportVO.setBodyList(resBodyList);
        return reportVO;
    }
}
